#include "hzpch.h"
#include "Log.h"

#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/basic_file_sink.h"
#include <filesystem>

namespace fs = std::filesystem;

namespace Hazel
{

    std::shared_ptr<spdlog::logger> Log::s_CoreLogger;
    std::shared_ptr<spdlog::logger> Log::s_ClientLogger;
    std::vector<spdlog::sink_ptr> Log::s_Sinks;

    void Log::Init()
    {
        try
        {
            // 1. 创建sinks（输出目标）
            s_Sinks.clear();

            // 控制台sink（带颜色）
            auto console_sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
            // console_sink->set_level(spdlog::level::level_enum.trace);
            s_Sinks.push_back(console_sink);

            // 文件sink
#ifdef _DEBUG
            const char *config = "Debug";
#else
            const char *config = "Release";
#endif

#ifdef _WIN64
            const char *platform = "x64";
#else
            const char *platform = "Win32";
#endif
            // 动态构建正确的输出目录路径
            fs::path output_dir;
            // 硬编码解决方案目录路径（根据您的实际路径修改）
            // output_dir = "E:\\Projects\\CPPProjects\\MyHazelEngin\\MyHazelEngin\\bin";
            // output_dir /= platform;
            // output_dir /= config;
            // output_dir /= "Hazel"; // 项目名称

            // 或者使用相对路径（从可执行文件位置计算）
            char exePath[MAX_PATH];
            GetModuleFileNameA(NULL, exePath, MAX_PATH);
            output_dir = fs::path(exePath).parent_path();

            fs::create_directories(output_dir);
            fs::path log_path = output_dir / "logs/hazel.log";
            fs::create_directories(log_path.parent_path());

            auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(log_path.string(), true);
            file_sink->set_pattern("[%T] [%l] %n: %v");
            s_Sinks.push_back(file_sink);

            // 2. 创建日志器并使用相同的sinks
            s_CoreLogger = std::make_shared<spdlog::logger>("HAZEL", s_Sinks.begin(), s_Sinks.end());
            s_CoreLogger->set_level(spdlog::level::trace);
            s_CoreLogger->flush_on(spdlog::level::err); // 错误级别时立即刷新

            s_ClientLogger = std::make_shared<spdlog::logger>("APP", s_Sinks.begin(), s_Sinks.end());
            s_ClientLogger->set_level(spdlog::level::trace);
            s_ClientLogger->flush_on(spdlog::level::err);

            // 3. 注册日志器
            spdlog::register_logger(s_CoreLogger);
            spdlog::register_logger(s_ClientLogger);

            // 4. 设置全局日志级别和异常处理
            spdlog::set_level(spdlog::level::trace);
            spdlog::set_error_handler([](const std::string &msg)
                                      { std::cerr << "Spdlog error: " << msg << std::endl; });

            HZ_CORE_INFO("Log system initialized");
            HZ_CORE_INFO("Log file: {}", log_path.string());
            HZ_CORE_INFO("Core logger has {} sinks", s_CoreLogger->sinks().size());
            HZ_CORE_INFO("Client logger has {} sinks", s_ClientLogger->sinks().size());
        }
        catch (const spdlog::spdlog_ex &ex)
        {
            std::cerr << "Log initialization failed: " << ex.what() << std::endl;
        }
        catch (const std::exception &ex)
        {
            std::cerr << "Failed to create log directory: " << ex.what() << std::endl;
        }
    }

    void Log::Shutdown()
    {
        HZ_CORE_INFO("Shutting down log system");
        spdlog::drop_all(); // 清理所有注册的日志器
        s_CoreLogger.reset();
        s_ClientLogger.reset();
        s_Sinks.clear();
    }
   
    void Log::SetCoreLogLevel(spdlog::level::level_enum level)
    {
        if (s_CoreLogger) {
            s_CoreLogger->set_level(level);
            HZ_CORE_INFO("Core log level set to: {}", spdlog::level::to_string_view(level));
        }
    }
   
    void Log::SetClientLogLevel(spdlog::level::level_enum level)
    {
        if (s_ClientLogger) {
            s_ClientLogger->set_level(level);
            HZ_CORE_INFO("Client log level set to: {}", spdlog::level::to_string_view(level));
        }
    }
   
    void Log::Flush()
    {
        if (s_CoreLogger) {
            s_CoreLogger->flush();
        }
        if (s_ClientLogger) {
            s_ClientLogger->flush();
        }
    }
}